﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace TestRunner {

    public class NameSpaceViewModel : ITestViewModel
    {
        readonly List<ITestViewModel> children;

        /// <summary>
        /// NOT used. Added to avoid binding errors.
        /// </summary>
        public string Result { get; set; }

        public bool CanRunIndependently 
        { 
            get { return false; }
            set 
            { 
                if (value)
                {
                    //Should always be false
                    NotifyPropertyChanged < NameSpaceViewModel>(p=> p.CanRunIndependently);
                }
            }
        }

        public NameSpaceViewModel(string namespaceName, ITestViewModel parent)
        {
            Name = namespaceName;
            children = new List<ITestViewModel>();
            IsInitiallySelected = false;
            Parent = parent;
        }

        public override List<ITestViewModel> Children { get { return children; } }
    }

    public class TestViewModel : ITestViewModel 
    {
        private string result;
        private string logPath;
        private string resultPath;
        

        public TestEntry TestEntry { get; private set; }
        public string Assembly { get { return TestEntry.Assembly; } }
        public string NamespaceName { get { return TestEntry.NameSpace; } }

        public string FullName { get { return TestEntry.FullName; } }

        public ObservableCollection<RunResultViewModel> RunResults { get; private set; }

        public string Result
        {
            get { return result; }
            set
            {
                result = value;
                NotifyPropertyChanged<TestViewModel>(p => p.Result);
            }
        }

        public string LogPath
        {
            get { return logPath; }
            set
            {
                logPath = value;
                NotifyPropertyChanged<TestViewModel>(p => p.LogPath);
            }
        }

        public string ResultPath
        {
            get { return resultPath; }
            set
            {
                resultPath = value;
                NotifyPropertyChanged<TestViewModel>(p => p.ResultPath);
            }
        }
        
        public bool CanRunIndependently 
        { 
            get { return TestEntry.CanRunIndependently; }
            set { TestEntry.CanRunIndependently = value; }
        }

        public override List<ITestViewModel> Children
        {
            get { return null; }
        }

        public TestViewModel(TestEntry testEntry, ITestViewModel parent)
        {
            RunResults = new ObservableCollection<RunResultViewModel>();

            TestEntry = testEntry;
            IsInitiallySelected = false;
            Parent = parent;
            Name = testEntry.ClassName;
            testEntry.PropertyChanged += testEntry_PropertyChanged;
        }

        void testEntry_PropertyChanged(object sender, PropertyChangedEventArgs e) 
        {
            if (e.PropertyName == "CanRunIndependently")
            {
                NotifyPropertyChanged<TestViewModel>(p => p.CanRunIndependently);
            }
        }
    }

    public abstract class ITestViewModel : ModelBase 
    {
        private RunState runState;
        public RunState State
        {
            get { return runState; }
            set 
            { 
                runState = value;
                NotifyPropertyChanged<ITestViewModel>(p => p.State);
            }
        }

        public abstract List<ITestViewModel> Children { get; }

        private bool? _isChecked = false;

        public bool? IsChecked
        {
            get { return _isChecked; }
            set
            {
                SetIsChecked(value, true, true);
            }
        }
        
        public ITestViewModel Parent { get; protected set; }

        public bool IsInitiallySelected { get; protected set; }
        public string Name { get; protected set; }

        void SetIsChecked(bool? value, bool updateChildren, bool updateParent)
        {
            if (value == _isChecked)
                return;

            _isChecked = value;

            if (updateChildren && _isChecked.HasValue && Children != null)
                Children.ForEach(c => c.SetIsChecked(_isChecked, true, false));

            if (updateParent && Parent != null)
                Parent.VerifyCheckState();

            NotifyPropertyChanged < ITestViewModel>(p => p.IsChecked);
        }

        void VerifyCheckState()
        {
            if (Children == null) return;
            bool? state = null;
            for (int i = 0; i < Children.Count; ++i)
            {
                bool? current = Children[i].IsChecked;
                if (i == 0)
                {
                    state = current;
                }
                else if (state != current)
                {
                    state = null;
                    break;
                }
            }
            SetIsChecked(state, false, true);
        }
    }
}
